﻿using System;
using System.Collections.Generic;
#if DEBUG
using System.Diagnostics;
#endif // #if DEBUG
using System.Linq;
using System.Text;
using System.Threading;

using FRL.DebtChased.Repository;
using FRL.DebtChased.ServiceUtilities;

using WorkflowObjects = FRL.DebtChased.WorkflowObjects.Workflow;

namespace FRL.DebtChased.ClockworkService
{

	/// <summary>
	/// Declaration of WorkflowWorker class
	/// </summary>
	class WorkflowWorker : BaseWorker
	{

		/////////////////////////////////////////////////////////////
		// TASKS:
		// Process workflow actions

		/////////////////////////////////////////////////////////////
		// Implementation

		protected override string ThreadName
		{
			get { return "Workflow"; }
		}

		protected override bool _doWork()
		{

			// Declare return variable
			bool bWorkDone = false;

			// Load the next account that needs processing soonest
			using (DebtChasedEntities ent = new DebtChasedEntities())
			{

				// Get the next account that needs processing
				Account acc = Account.GetNextAccountForWorkflowProcessing(ent);
				if (acc != null)
				{

					// Try and lock this account and workflows
					string strLockingError = RecentActivity.AttemptLock(ent, "tbAccount", acc.AccountId, null);
					if (strLockingError == null)
					{

						// Update log
						_appendToLog(string.Format("Found account {0}", acc.FRLReference));

						// Process this account
						_fnWorker_ProcessAccount(ent, acc);

						// Update flag 
						bWorkDone = true;

					}
					else
						_appendToLog(strLockingError);

				}				

			}

			// Return variable
			return bWorkDone;

		}

		/////////////////////////////////////////////////////////////
		// Operations

		private void _fnWorker_ProcessAccount(DebtChasedEntities ent, Account acc)
		{

			// Loop through the invoices, knocking them off in groups
			List<AccountInvoice> copyInv = new List<AccountInvoice>();
			copyInv.AddRange(acc.AccountInvoices);
			while(copyInv.Count>0)
			{

				// Get the next invoice
				AccountInvoice accInv = copyInv[0];

				// If this invoice DOES NOT need processing, or DOES NOT have a workflow, or IS NOT due...
				if ( (!accInv.IsProcessingDue) || (accInv.WorkflowId==null) || (!accInv.IsProcessingDue) )
				{

					// Remove from list and continue
					copyInv.RemoveAt(0);
					continue;

				}

				// Find all invoices that use this workflow
				List<AccountInvoice> invGroup = new List<AccountInvoice>();
				invGroup.Add(accInv);
				for (int i1 = 1; i1 < copyInv.Count; i1++)
				{
					if(copyInv[i1].WorkflowId == accInv.WorkflowId)
						invGroup.Add(copyInv[i1]);
				}

				// Get the workflow id and name
				int iWorkflowId = accInv.WorkflowId.Value;
				string strWorkflow = Workflow.GetName(ent, iWorkflowId);

				// Lock and load the workflow
				string strLockingError = RecentActivity.AttemptLock(ent, "tbWorkflow", iWorkflowId, null);
				if (strLockingError == null)
				{

					// Load the workflow
					WorkflowObjects.Workflow wf = Workflow.GetWorkflow(ent, iWorkflowId);

					// Loop through the invoice group
					foreach (AccountInvoice inv in invGroup)
					{

						// Calculate the day
						TimeSpan span1 = DateTime.Now - inv.WorkflowDay1.Value;
						int iDay = (int)Math.Floor(span1.TotalDays + 1);

						// Loop through the actions for this day
						List<WorkflowObjects.WorkflowAction_Base> actions = wf.GetActionsOnDay(iDay);
						foreach (WorkflowObjects.WorkflowAction_Base action in actions)
						{

							// Has this workflow item already been executed for this invoice?
							if (AccountNote.FindWorkflowActionGuid(ent, inv.AccountInvoiceId, action.Identifier))
								_appendToLog(string.Format("Workflow task {0} already processed for invoice {1}", action.GetSummary(WorkflowObjects.Workflow.eSummaryFormat.Clockwork), inv.InvoiceNo));
							else
							{
								List<AccountNote> newNotes = action.Process(ent, acc, inv);
								if ((newNotes != null) && (newNotes.Count > 0))
								{
									foreach (AccountNote note in newNotes)
										LogFile.Append(note);
								}
							}

						}

					}

				}
				else
				{

					// Log message
					_appendToLog(string.Format("Cannot lock workflow {0}", strWorkflow));

				}

				// Remove this invoice group from the copy-list
				foreach (AccountInvoice inv in invGroup)
					copyInv.Remove(inv);

			}

		}

	}

}
